package org.droidfly;

import java.io.IOException;
import java.util.Vector;

import org.droidfly.ServoControlService1.ServoControlServiceBinder;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.*;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class DroidFly extends Activity implements OnSeekBarChangeListener {

	// Debugging
	private static final String TAG = "DroidFly";
	private static final boolean D = true;

	// Message types sent from the ServoControlService Handler
	public static final int MESSAGE_STATE_CHANGE = 1;
	public static final int MESSAGE_READ = 2;
	public static final int MESSAGE_WRITE = 3;
	public static final int MESSAGE_DEVICE_NAME = 4;
	public static final int MESSAGE_TOAST = 5;

	// Key names received from the ServoControlService Handler
	public static final String TOAST = "toast";
	public static final String DEVICE_NAME = "device_name";

	// Intent request codes
	private static final int REQUEST_CONNECT_DEVICE = 1;
	private static final int REQUEST_ENABLE_BT = 2;

	private Button btnMin;
	private Button btnMax;
	private TextView mTitleLeft;
	private TextView mTitleRight;

	private Vector<TextView> labels;
	private Vector<SeekBar> seekBars;

	// Name of the connected device
	private String mConnectedDeviceName = null;
		
	// Local Bluetooth adapter
	private BluetoothAdapter mBluetoothAdapter = null;
	
	private BluetoothDevice mBlueToothDevice = null;
	// Member object for the chat services
	//private ServoControlService mServoControlService = null;

	private final int MAX_PROGRESS = 255;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (D)
			Log.e(TAG, "+++ ON CREATE +++");

		// Set up the window layout
		requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
		setContentView(R.layout.servo_test);
		getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
				R.layout.custom_title);

		// Set up the custom title
		mTitleLeft = (TextView) findViewById(R.id.title_left_text);
		mTitleLeft.setText(R.string.app_name);
		mTitleRight = (TextView) findViewById(R.id.title_right_text);

		// Get local Bluetooth adapter
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

		// If the adapter is null, then Bluetooth is not supported
		if (mBluetoothAdapter == null) {
			Toast.makeText(this, "Bluetooth is not available",
					Toast.LENGTH_LONG).show();
			finish();
			return;
		}
	}

	@Override
	public void onStart() {
		super.onStart();
		if (D)
			Log.e(TAG, "++ ON START ++");

		setup();

		// If BT is not on, request that it be enabled.
		// setupChat() will then be called during onActivityResult
		// if (!mBluetoothAdapter.isEnabled()) {
		// Intent enableIntent = new Intent(
		// BluetoothAdapter.ACTION_REQUEST_ENABLE);
		// startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
		// // Otherwise, setup the chat session
		// } else {
		// if (mServoControlService == null)
		// setup();
		// }

		// Bind to Service
		// Intent intent = new Intent(this, ServoControlService1.class);
		// bindService(intent, servoControlServiceConnection,
		// Context.BIND_AUTO_CREATE);
	}

	@Override
	public synchronized void onResume() {
		super.onResume();
		if (D)
			Log.e(TAG, "+ ON RESUME +");

		// Performing this check in onResume() covers the case in which BT was
		// not enabled during onStart(), so we were paused to enable it...
		// onResume() will be called when ACTION_REQUEST_ENABLE activity
		// returns.
		// if (mServoControlService != null) {
		// // Only if the state is STATE_NONE, do we know that we haven't
		// // started already
		// if (mServoControlService.getState() ==
		// ServoControlService.STATE_NONE) {
		// // Start the Bluetooth chat services
		// mServoControlService.start();
		// }
		// }
	}

	@Override
	public synchronized void onPause() {
		super.onPause();
		if (D)
			Log.e(TAG, "- ON PAUSE -");
	}	
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		// Unbind from the service
		if (isServoControlServiceBound) {
			unbindService(servoControlServiceConnection);
			isServoControlServiceBound = false;
		}
	}

//	@Override
//	public void onDestroy() {
//		super.onDestroy();
//		// Stop the Bluetooth chat services
//		if (mServoControlService != null)
//			mServoControlService.stop();
//
//		if (D)
//			Log.e(TAG, "--- ON DESTROY ---");
//	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.option_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.scan:
			if (!mBluetoothAdapter.isEnabled()) {
				Intent enableIntent = new Intent(
						BluetoothAdapter.ACTION_REQUEST_ENABLE);
				startActivityForResult(enableIntent, REQUEST_ENABLE_BT);

			} else {
				if(isServoControlServiceBound){
					unbindService(servoControlServiceConnection);
					isServoControlServiceBound = false;
				}
				// Launch the DeviceListActivity to see devices and do scan
				Intent serverIntent = new Intent(this, DeviceListActivity.class);
				startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
			}

			return true;
		case R.id.sensors:
			// Launch the DeviceListActivity to see devices and do scan
			Intent sensorsIntent = new Intent(this, SensorsActivity.class);
			startActivity(sensorsIntent);
			return true;
			// case R.id.discoverable:
			// // Ensure this device is discoverable by others
			// ensureDiscoverable();
			// return true;
		}
		return false;
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (D)
			Log.d(TAG, "onActivityResult " + resultCode);
		switch (requestCode) {
		case REQUEST_CONNECT_DEVICE:
			// When DeviceListActivity returns with a device to connect
			if (resultCode == Activity.RESULT_OK) {
				// Get the device MAC address				
				String address = data.getExtras().getString(
						DeviceListActivity.EXTRA_DEVICE_ADDRESS);
				// Get the BLuetoothDevice object
				mBlueToothDevice = mBluetoothAdapter
						.getRemoteDevice(address);
				// Bind to Service
				Intent intent = new Intent(this, ServoControlService1.class);				
				bindService(intent, servoControlServiceConnection,
						Context.BIND_AUTO_CREATE);				
			}
			break;
		case REQUEST_ENABLE_BT:
			// When the request to enable Bluetooth returns
			if (resultCode == Activity.RESULT_OK) {
				// Bluetooth is now enabled, so set up a chat session
				//setup();
				Intent serverIntent = new Intent(this, DeviceListActivity.class);
				startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
			} else {
				// User did not enable Bluetooth or an error occured
				Log.d(TAG, "BT not enabled");
				Toast.makeText(this, R.string.bt_not_enabled_leaving,
						Toast.LENGTH_SHORT).show();
				finish();
			}
		}
	}

	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		performProgressChanged(seekBar, progress, fromUser);
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
	}

	private void setup() {
		Log.d(TAG, "setup");

		labels = new Vector<TextView>();
		seekBars = new Vector<SeekBar>();

		// Initialize the send button with a listener that for click events
		btnMin = (Button) findViewById(R.id.btnMinValue);
		btnMin.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				setAllSeekBarsToMin();
			}
		});

		btnMax = (Button) findViewById(R.id.btnMaxValue);
		btnMax.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				setAllSeekBarsToMax();
			}
		});

		labels.add((TextView) findViewById(R.id.txvChannel1));
		labels.add((TextView) findViewById(R.id.txvChannel2));
		labels.add((TextView) findViewById(R.id.txvChannel3));
		labels.add((TextView) findViewById(R.id.txvChannel4));
		labels.add((TextView) findViewById(R.id.txvChannel5));

		seekBars.add((SeekBar) findViewById(R.id.seekBar1));
		seekBars.add((SeekBar) findViewById(R.id.seekBar2));
		seekBars.add((SeekBar) findViewById(R.id.seekBar3));
		seekBars.add((SeekBar) findViewById(R.id.seekBar4));
		seekBars.add((SeekBar) findViewById(R.id.seekBar5));

		for (SeekBar seekBar : this.seekBars) {
			seekBar.setMax(this.MAX_PROGRESS);
			seekBar.setOnSeekBarChangeListener(this);
		}

		// this.mServoControlService = new ServoControlService(this,
		// scsMsgHandler);
	}

	private void setAllSeekBarsToMin() {
		for (SeekBar seekBar : this.seekBars) {
			seekBar.setProgress(0);
		}
	}

	private void setAllSeekBarsToMax() {
		for (SeekBar seekBar : this.seekBars) {
			seekBar.setProgress(seekBar.getMax());
		}
	}

	private void performProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {

		if (null == servoControlService)
			return;

		TextView lblChannel = this.getLabelBySeekBar(seekBar);
		lblChannel.setText(String.valueOf(progress));
		int servo = this.getServoNumberBySeekBar(seekBar);

		try {
			// mServoControlService.moveServoToPosition(servo, progress);
			servoControlService.moveServoToPosition(servo, progress);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private TextView getLabelBySeekBar(SeekBar seekBar) {
		int seekBarIndex = seekBars.indexOf(seekBar);
		return labels.elementAt(seekBarIndex);
	}

	private int getServoNumberBySeekBar(SeekBar seekBar) {
		return seekBars.indexOf(seekBar);
	}

	// private void ensureDiscoverable() {
	// if (D)
	// Log.d(TAG, "ensure discoverable");
	// if (mBluetoothAdapter.getScanMode() !=
	// BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
	// Intent discoverableIntent = new Intent(
	// BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
	// discoverableIntent.putExtra(
	// BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
	// startActivity(discoverableIntent);
	// }
	// }

	// The Handler that gets information back from the BluetoothChatService
	private final Handler scsMsgHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case MESSAGE_STATE_CHANGE:
				if (D)
					Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
				switch (msg.arg1) {
				case ServoControlService1.STATE_CONNECTED:
					mTitleRight.setText(R.string.title_connected_to);
					mTitleRight.append(mConnectedDeviceName);
					// mConversationArrayAdapter.clear();
					break;
				case ServoControlService1.STATE_CONNECTING:
					mTitleRight.setText(R.string.title_connecting);
					break;
				case ServoControlService1.STATE_NONE:
					mTitleRight.setText(R.string.title_not_connected);
					break;
				}
				
				break;
			case MESSAGE_WRITE:
				byte[] writeBuf = (byte[]) msg.obj;
				// construct a string from the buffer
				String writeMessage = new String(writeBuf);
				if (D)
					Log.d(TAG, "sent " + writeMessage);
				break;
			case MESSAGE_READ:
				byte[] readBuf = (byte[]) msg.obj;
				// construct a string from the valid bytes in the buffer
				String readMessage = new String(readBuf, 0, msg.arg1);
				if (D)
					Log.d(TAG, "recived  " + readMessage);
				break;
			case MESSAGE_DEVICE_NAME:
				// save the connected device's name
				mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
				Toast.makeText(getApplicationContext(),
						"Connected to " + mConnectedDeviceName,
						Toast.LENGTH_SHORT).show();
				break;
			case MESSAGE_TOAST:
				Toast.makeText(getApplicationContext(),
						msg.getData().getString(TOAST), Toast.LENGTH_SHORT)
						.show();
				break;
			}
		}
	};

	// / SERVICE

	private boolean isServoControlServiceBound = false;
	private ServoControlService1 servoControlService = null;
	/** Defines callbacks for service binding, passed to bindService() */
	private ServiceConnection servoControlServiceConnection = new ServiceConnection() {

		@Override
		public void onServiceConnected(ComponentName className, IBinder service) {
			// We've bound to LocalService, cast the IBinder and get
			// LocalService instance
			ServoControlServiceBinder binder = (ServoControlServiceBinder) service;
			servoControlService = binder.getService();
			servoControlService.setHandler(scsMsgHandler);
			
			// Attempt to connect to the device
			servoControlService.connect(mBlueToothDevice);			
			isServoControlServiceBound = true;
		}

		@Override
		public void onServiceDisconnected(ComponentName arg0) {
			isServoControlServiceBound = false;
		}
	};

}